/**
 ThreadLocal 为每个线程提供独立的数据副本，实现线程隔离，避免多线程环境下的数据竞争问题。
 通过线程绑定机制，数据可在调用链中隐式传递，无需显式方法参数传递。线程终止时自动清理关联数据，防止内存泄漏。
 */
package cn.edu.sdjzu.xg.eagle.filter;
import cn.edu.sdjzu.xg.eagle.util.ConfigUtil;
import cn.edu.sdjzu.xg.eagle.util.JwtUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
 * JWT认证过滤器
 * 负责验证受保护端点的令牌有效性及用户身份
 */
@WebFilter(filterName = "Jwt Filter", urlPatterns = {"/*"})
@Slf4j
public class JwtAuthFilter implements Filter {

    private static final String BEARER_PREFIX = "Bearer ";
    private static final String AUTH_HEADER = "Authorization";
    private static final ThreadLocal<String> currentUserId = new ThreadLocal<>();

    // 免认证路径（这些路径跳过身份验证）
    private static final Set<String> WHITELISTED_PATHS = new HashSet<>(Arrays.asList(
            "/login.ctl",   // 登录接口
            "/health",      // 健康检查接口
            "/swagger-ui.html", // Swagger文档页面
            "/swagger-resources", // Swagger资源
            "/v2/api-docs", // API文档
            "/webjars"      // 静态资源
    ));

    @Override
    public void init(FilterConfig filterConfig) {
        log.info("JWT authentication filter initialized");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String path = request.getRequestURI();

        try {
            // 检查路径是否在免认证列表中
            if (isWhitelisted(path)) {
                log.debug("Bypassing authentication for whitelisted path: {}", path);
                filterChain.doFilter(request, response);
                return;
            }

            // 验证授权头信息
            String token = extractToken(request);
            if (token == null) {
                sendUnauthorized(response, "缺少或无效的授权头信息");
                return;
            }

            // 验证令牌
            if (!JwtUtil.validateToken(token)) {
                sendUnauthorized(response, "无效或已过期的令牌");
                return;
            }

            // 处理有效令牌
            DecodedJWT decodedJWT = JWT.decode(token);
            currentUserId.set(decodedJWT.getSubject());

            log.debug("Successfully authenticated request for path: {}", path);
            filterChain.doFilter(request, response);

        } finally {
            currentUserId.remove(); // 总是清理线程本地变量
            log.trace("Cleared currentUserId from ThreadLocal");
        }
    }

    @Override
    public void destroy() {
        log.info("JWT authentication filter destroyed");
    }

    public static String getCurrentUserId() {
        return currentUserId.get();
    }

    private boolean isWhitelisted(String path) {
        return WHITELISTED_PATHS.stream().anyMatch(path::endsWith);
    }

    private String extractToken(HttpServletRequest request) {
        String authHeader = request.getHeader(AUTH_HEADER);
        if (authHeader == null || !authHeader.startsWith(BEARER_PREFIX)) {
            return null;
        }
        return authHeader.substring(BEARER_PREFIX.length()).trim();
    }

    private void sendUnauthorized(HttpServletResponse response, String message) throws IOException {
        log.warn("Authentication failed: {}", message);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getWriter().write("{\"错误\":\"" + message + "\"}");
        response.setContentType("application/json;charset=UTF-8");
    }
}